// Standard C++ includes
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <cstring>

#include <mysql_connection.h>
#include <mysql_driver.h>

#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>

#include "DataBase.h"
#include "ServicioDB.h"

using namespace std;

ServicioDB::ServicioDB()
{
}

/**
  Busca un servicio por el ID del servicio
  Entrada: ID del servicio a buscar
  Salida: Servicio que coincidio con la busqueda lleno con todos los datos llenos, en caso de que
  no se encuentre nada, se retornara un Servicio Vacio.
*/
Servicio ServicioDB::getByID(int idServicio){
    sql::Driver * driver = sql::mysql::get_driver_instance();
    /* Usando el Driver se pide una coneccion */
    std::auto_ptr< sql::Connection > con(driver->connect(HOST_URL, USER, PASS));

    /* Se crea un Statement */
    std::auto_ptr< sql::Statement > stmt(con->createStatement());

    //Se señala la base de datos a utilizar
    stringstream sqlDB;
    sqlDB.str("");
    sqlDB << "USE " <<DB_NAME;
    stmt->execute(sqlDB.str());

    //Se crea la consulta
    stringstream sql;
    sql.str("");
    sql << "SELECT * FROM Servicio WHERE idServicio ="<< idServicio <<";";

    //Se crea el Result Set a partir de la consulta deseada
    std::auto_ptr< sql::ResultSet > res(stmt->executeQuery(sql.str()));
    //cout<<"Consulta: "<< "SELECT * FROM Cuenta WHERE noCuenta ="<< noCuenta <<";"<<endl;

    /* Numero de rows en el result set */
    //cout << "#\t\t Rows Count: \t";
    //cout << "res->rowsCount() = " << res->rowsCount() << endl;

    sql::SQLString cad;
    cad.asStdString();
    /* Obtener Datos */
    while (res->next()) {
        Servicio s = Servicio();
        //Se obtiene la compania del ResultSet
        sql::SQLString com = res->getString("compania");
        //Se crea un char* para almacenar dicha compania
        char *companiaRes = new char[com.asStdString().size() + 1];
        //Se copia el contenido de la cadena
        std::strcpy ( companiaRes, com.c_str() );

        s.setCompania(companiaRes);

        //Se obtiene la descripcion del ResultSet
        sql::SQLString des = res->getString("descripcion");
        //Se crea un char* para almacenar dicha descripcion
        char *descripcionRes= new char[des.asStdString().size() + 1];
        //Se copia el contenido de la cadena
        std::strcpy ( descripcionRes, des.c_str() );
        s.setDescripcion(descripcionRes);

        s.setNoCuenta(res->getInt("noCuenta"));
        s.setIdServicio(res->getInt("idServicio"));

        stmt.reset(NULL); /* Limpiar el objeto  */
        con.reset(driver->connect(HOST_URL, USER, PASS));
        return s;
    }

    stmt.reset(NULL); /* Limpiar el objeto  */
    con.reset(driver->connect(HOST_URL, USER, PASS));
    return Servicio();
}

/**
  Busca servicios a partir del nombre de la compañia, la busqueda se hara con LIKE %[NombreCompañia]%
  Entrada: Nombre de la compañia a buscar, Referencia al Numero de Rows encontrado en la base de datos
  Salida: Arreglo de Servicios que coincidieron con la busqueda
 */
Servicio* ServicioDB::getByCompania(char *compania, int &rows){
    sql::Driver * driver = sql::mysql::get_driver_instance();
    /* Usando el Driver se pide una coneccion */
    std::auto_ptr< sql::Connection > con(driver->connect(HOST_URL, USER, PASS));

    /* Se crea un Statement */
    std::auto_ptr< sql::Statement > stmt(con->createStatement());

    //Se señala la base de datos a utilizar
    stringstream sqlDB;
    sqlDB.str("");
    sqlDB << "USE " <<DB_NAME;
    stmt->execute(sqlDB.str());

    //Se crea la consulta
    stringstream sql;
    sql.str("");
    sql << "SELECT * FROM Servicio WHERE compania LIKE '%"<< compania <<"%';";

    //Se crea el Result Set a partir de la consulta deseada
    std::auto_ptr< sql::ResultSet > res(stmt->executeQuery(sql.str()));
    //cout<<"Consulta: "<< "SELECT * FROM Cuenta WHERE noCuenta ="<< noCuenta <<";"<<endl;

    /* Numero de rows en el result set */
    cout << "#\t\t Rows Count: \t";
    cout << "res->rowsCount() = " << res->rowsCount() << endl;

    rows = res->rowsCount();

    Servicio* servicios = new Servicio[res->rowsCount()];
    /* Obtener Datos */
    int row = 0;
    while (res->next()) {
        servicios[row] = Servicio();
        //Se obtiene la compania del ResultSet
        sql::SQLString com = res->getString("compania");
        //Se crea un char* para almacenar dicha compania
        char *companiaRes = new char[com.asStdString().size() + 1];
        //Se copia el contenido de la cadena
        std::strcpy ( companiaRes, com.c_str() );
        servicios[row].setCompania(companiaRes);

        //Se obtiene la descripcion del ResultSet
        sql::SQLString des = res->getString("descripcion");
        //Se crea un char* para almacenar dicha descripcion
        char *descripcionRes= new char[des.asStdString().size() + 1];
        //Se copia el contenido de la cadena
        std::strcpy ( descripcionRes, des.c_str() );
        servicios[row].setDescripcion(descripcionRes);

        servicios[row].setNoCuenta(res->getInt("noCuenta"));
        servicios[row].setIdServicio(res->getInt("idServicio"));
        row++;
    }

    stmt.reset(NULL); /* Limpiar el objeto  */
    con.reset(driver->connect(HOST_URL, USER, PASS));
    return servicios;
}

/**
  Actualiza un registro de Servicio COMPLETO en la base de datos
  Entrada: Servicio a actualiza,
        IMPORTANTE: Se actualizaran TODOS los campos de la clase
  Salida: True si se actualizo correctamente, False en otro caso
*/
bool ServicioDB::update(Servicio servicio){
    sql::Driver * driver = sql::mysql::get_driver_instance();
    /* Usando el Driver se pide una coneccion */
    std::auto_ptr< sql::Connection > con(driver->connect(HOST_URL, USER, PASS));

    /* Se crea un Statement */
    std::auto_ptr< sql::Statement > stmt(con->createStatement());

    //Se señala la base de datos a utilizar
    stringstream sqlDB;
    sqlDB.str("");
    sqlDB << "USE " <<DB_NAME;
    stmt->execute(sqlDB.str());

    //Se crea la consulta
    stringstream sql;
    sql.str("");
    sql << "UPDATE Servicio SET compania= '"<<servicio.getCompania()<<"', descripcion='"
        <<servicio.getDescripcion()<<"', noCuenta="<<servicio.getNoCuenta()
        <<"  WHERE idServicio= "<< servicio.getIdServicio()<<";";
    int affected_rows = stmt->executeUpdate(sql.str());

    stmt.reset(NULL); /* Limpiar el objeto  */
    con.reset(driver->connect(HOST_URL, USER, PASS));
    //Si se afecto mas de una fila regresar true, de lo contrario regresar false
    return affected_rows > 0? true:false;
}
